/*
 * @author: liubing
 * @Date: 2020-12-16 20:20:37
 * @desc: 作业10
 */


//  设备device,既 GL
var device = null;
var gl = null;


var d = {}
var g_cubeInfo;
var g_LightCubeInfo;
var g_boxInfo;

// 可以用滑块控制的放在这里

var lightCubeSize = 10
var lightCubePos = [10, 4, 120];
var cameraPos = [160, 170, 200]

var boxSize = 60;
var boxPos = [-0, 60, -0];

var ambientLight = [0.2, 0.2, 0.2];

var pointlight = [0,1,0];
// 
var shininess = 150;
var innerLimit = 10;
var outerLimit = 20;
var lightRotationX = 30;
var lightRotationY = 0;
var lightDirection = [0.5, 0.5, 1]; // this is computed in updateScene


function radToDeg(r) {
    return r * 180 / Math.PI;
}

function degToRad(d) {
    return d * Math.PI / 180;
}

// 地面

var floorSize = 500;
var g_floorInfo;


function main() {
    console.log("main() -> ");
    if (!initGL()) {
        return;
    }

    initUI();

    loadTexture(gl, 'resources/container.jpg', function (texture) {
        d.cubeTexture = texture
    });

    loadTexture(gl, 'resources/concrete1.jpg', function (texture) {
        // g_boxInfo.texture = texture
        d.texture = texture;
        draw();
    })
}

function initGL() {
    console.log("init GL");
    const canvas = document.getElementById("canvas_1");
    device = canvas.getContext("webgl");
    if (!device) {
        alert("WebGL Device accquire error");
        return false;
    }
    gl = device;

    console.log(canvas);
    d.canvas = canvas;
    canvas.width = canvas.clientWidth;
    canvas.height = canvas.clientHeight;
    d.width = canvas.width;
    d.height = canvas.height;
    device.viewport(0, 0, d.width, d.height);

    setupMatrix();
    setupCubeData();

    return true;
}


// UI 觉得使用 WebLessonUI 库
function initUI() {
    console.log("init UI");


    webglLessonsUI.setupSlider("#lightCubeSize", {
        value: lightCubeSize,
        slide: function (event, ui) {
            lightCubeSize = ui.value;
            draw()
        },
        min: 1,
        max: 40,
        step: 0.1,
        precision: 0
    });

    webglLessonsUI.setupSlider("#light_X", {
        value: lightCubePos[0],
        slide: function (event, ui) {
            lightCubePos[0] = ui.value;
            draw()
        },
        min: -240,
        max: 240,
        step: 0.1,
        precision: 0
    });

    webglLessonsUI.setupSlider("#light_Y", {
        value: lightCubePos[1],
        slide: function (event, ui) {
            lightCubePos[1] = ui.value;
            draw()
        },
        min: -240,
        max: 240,
        step: 0.1,
        precision: 0
    });

    webglLessonsUI.setupSlider("#light_Z", {
        value: lightCubePos[2],
        slide: function (event, ui) {
            lightCubePos[2] = ui.value;
            draw()
        },
        min: -240,
        max: 240,
        step: 0.1,
        precision: 0
    });

    webglLessonsUI.setupSlider("#boxSize", {
        value: boxSize,
        slide: function (event, ui) {
            boxSize = ui.value;
            draw()
        },
        min: 2,
        max: 100,
        step: 0.1,
        precision: 0
    });

    webglLessonsUI.setupSlider("#box_X", {
        value: boxPos[0],
        slide: function (event, ui) {
            boxPos[0] = ui.value;
            draw()
        },
        min: -120,
        max: 120,
        step: 0.1,
        precision: 0
    });

    webglLessonsUI.setupSlider("#box_Y", {
        value: boxPos[1],
        slide: function (event, ui) {
            boxPos[1] = ui.value;
            draw()
        },
        min: -120,
        max: 120,
        step: 0.1,
        precision: 0
    });

    webglLessonsUI.setupSlider("#box_Z", {
        value: boxPos[2],
        slide: function (event, ui) {
            boxPos[2] = ui.value;
            draw()
        },
        min: -240,
        max: 120,
        step: 0.1,
        precision: 0
    });

    webglLessonsUI.setupSlider("#camera_X", {
        value: cameraPos[0],
        slide: function (event, ui) {
            cameraPos[0] = ui.value;
            draw()
        },
        min: -480,
        max: 480,
        step: 0.1,
        precision: 0
    });

    webglLessonsUI.setupSlider("#camera_Y", {
        value: cameraPos[1],
        slide: function (event, ui) {
            cameraPos[1] = ui.value;
            draw()
        },
        min: -240,
        max: 480,
        step: 0.1,
        precision: 0
    });

    webglLessonsUI.setupSlider("#camera_Z", {
        value: cameraPos[2],
        slide: function (event, ui) {
            cameraPos[2] = ui.value;
            draw()
        },
        min: -240,
        max: 480,
        step: 0.1,
        precision: 0
    });

    webglLessonsUI.setupSlider("#lightRotationX", {
        value: lightRotationX,
        slide: function (event, ui) {
            lightRotationX = ui.value;
            draw()
        },
        min: -180,
        max: 180,
        step: 1,
        precision: 0,
    });

    webglLessonsUI.setupSlider("#lightRotationY", {
        value: lightRotationY,
        slide: function (event, ui) {
            lightRotationY = ui.value;
            draw()
        },
        min: -180,
        max: 180,
        step: 1,
        precision: 0
    });
    webglLessonsUI.setupSlider("#innerLimit", {
        value: innerLimit,
        slide: function (event, ui) {
            innerLimit = ui.value;
            draw()
        },
        min: 0,
        max: 180
    });
    webglLessonsUI.setupSlider("#outerLimit", {
        value: outerLimit,
        slide: function (event, ui) {
            outerLimit = ui.value;
            draw()
        },
        min: 0,
        max: 180
    });

    webglLessonsUI.setupSlider("#pointLight_R", {
        value: pointlight[0],
        slide: function (event, ui) {
            pointlight[0] = ui.value;
            draw()
        },
        min: 0,
        max: 1,
        step:0.01,
        precision:2,
    });
    webglLessonsUI.setupSlider("#pointLight_G", {
        value: pointlight[1],
        slide: function (event, ui) {
            pointlight[1] = ui.value;
            draw()
        },
        min: 0,
        max: 1,
        step:0.01,
        precision:2,
    });
    webglLessonsUI.setupSlider("#pointLight_B", {
        value: pointlight[2],
        slide: function (event, ui) {
            pointlight[2] = ui.value;
            draw()
        },
        min: 0,
        max: 1,
        step:0.01,
        precision:2,
    });
}


// WebGL 与 二进制文件一个区别在于 可以不放在循环中查看渲染效果
function draw() {
    console.log("draw() -> ", d.width, d.height);

    gl.clearColor(0.3, 0.3, 0.3, 1);
    gl.clearDepth(1.0); // Clear everything
    gl.enable(gl.DEPTH_TEST); // Enable depth testing
    gl.depthFunc(gl.LEQUAL); // Near things obscure far things
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    updateMatrix();

    drawLightCube(lightCubeSize, lightCubePos);
    drawBox(boxSize, boxPos);
    drawFloor(floorSize);
}

// 设置矩阵
function setupMatrix() {
    console.log("setupMatrix()");

    const fieldOfView = 45; //这里是角度，与WebFxxxx 的库不同
    const aspect = d.width / d.height;
    const zNear = 1;
    const zFar = 1000;

    // 投影矩阵
    let projectionMatrix = new Matrix4();
    projectionMatrix.setPerspective(fieldOfView, aspect, zNear, zFar);
    d.projectionMatrix = projectionMatrix;
    console.log('projectionMatrix', projectionMatrix);


}

function updateMatrix() {
    // 视图矩阵
    var target = [0, 0, 0];
    var up = [0, 1, 0];
    let viewMatrix = new Matrix4();
    viewMatrix.setLookAt(...cameraPos, ...target, ...up)
    d.viewMatrix = viewMatrix;
    console.log('viewMatrix', viewMatrix);
}
// 
function setupCubeData() {

    let positions = [
        //前面
        -1.0, -1.0, 1.0,
        1.0, -1.0, 1.0,
        1.0, 1.0, 1.0,
        -1.0, 1.0, 1.0,

        //后 
        -1.0, -1.0, -1.0,
        -1.0, 1.0, -1.0,
        1.0, 1.0, -1.0,
        1.0, -1.0, -1.0,
        

        //上
        -1.0, 1.0, -1.0,
        -1.0, 1.0, 1.0,
        1.0, 1.0, 1.0,
        1.0, 1.0, -1.0,

        //下
        -1.0, -1.0, -1.0,
        1.0, -1.0, -1.0,
        1.0, -1.0, 1.0,
        -1.0, -1.0, 1.0,

        //左
        -1.0, -1.0, -1.0,
        -1.0, -1.0, 1.0,
        -1.0, 1.0, 1.0,
        -1.0, 1.0, -1.0,

        //右边
        1.0, -1.0, -1.0,
        1.0, 1.0, -1.0,
        1.0, 1.0, 1.0,
        1.0, -1.0, 1.0,
    ];

    const faceColors = [
        [1.0, 0.0, 0.0, 1.0], // Front face: white
        [1.0, 0.0, 0.0, 1.0], // Back face: red
        [0.0, 1.0, 0.0, 1.0], // Top face: green
        [0.0, 0.0, 1.0, 1.0], // Bottom face: blue
        [1.0, 1.0, 0.0, 1.0], // Right face: yellow
        [1.0, 0.0, 1.0, 1.0], // Left face: purple
    ];

    let colors = [];
    for (var j = 0; j < faceColors.length; ++j) {
        const c = faceColors[j];
        colors = colors.concat(c, c, c, c);
    }


    // 法线
    let normals = [
        // Front
        0.0, 0.0, 1.0,
        0.0, 0.0, 1.0,
        0.0, 0.0, 1.0,
        0.0, 0.0, 1.0,

        // Back
        0.0, 0.0, -1.0,
        0.0, 0.0, -1.0,
        0.0, 0.0, -1.0,
        0.0, 0.0, -1.0,

        // Top
        0.0, 1.0, 0.0,
        0.0, 1.0, 0.0,
        0.0, 1.0, 0.0,
        0.0, 1.0, 0.0,

        // Bottom
        0.0, -1.0, 0.0,
        0.0, -1.0, 0.0,
        0.0, -1.0, 0.0,
        0.0, -1.0, 0.0,

        // Left
        -1.0, 0.0, 0.0,
        -1.0, 0.0, 0.0,
        -1.0, 0.0, 0.0,
        -1.0, 0.0, 0.0,
        // Right
        1.0, 0.0, 0.0,
        1.0, 0.0, 0.0,
        1.0, 0.0, 0.0,
        1.0, 0.0, 0.0,


    ];
    // 索引
    let indices = [
        0, 1, 2, 0, 2, 3,
        4, 5, 6, 4, 6, 7,
        8, 9, 10, 8, 10, 11,
        12, 13, 14, 12, 14, 15,
        16, 17, 18, 16, 18, 19,
        20, 21, 22, 20, 22, 23,
    ];

    // 纹理
    const textureIndies = [
        //front
        0.0, 0.0,
        1.0, 0.0,
        1.0, 1.0,
        0.0, 1.0,

        //back
        0.0, 0.0,
        1.0, 0.0,
        1.0, 1.0,
        0.0, 1.0,

        //left
        0.0, 0.0,
        1.0, 0.0,
        1.0, 1.0,
        0.0, 1.0,
        //right
        0.0, 0.0,
        1.0, 0.0,
        1.0, 1.0,
        0.0, 1.0,
        //bottom
        0.0, 0.0,
        1.0, 0.0,
        1.0, 1.0,
        0.0, 1.0,
        //top
        0.0, 0.0,
        1.0, 0.0,
        1.0, 1.0,
        0.0, 1.0,
    ];

    d.cubeData = {
        positions: positions,
        colors: colors,
        indices: indices,
        textureIndies: textureIndies,
        normals: normals,
    };
}

// 画地板
function drawFloor(floorSize) {
    console.log("drawFloor -> ", floorSize);
    if (!g_floorInfo) {
        g_floorInfo = {
            buffers: initBuffer(),
            programInfo: initProgramInfo(),
        }
    }

    function initBuffer() {
        // position
        let positions = [
            -1, 0, 1,
            1, 0, 1,
            1, 0, -1,
            -1, 0, -1
        ];
        // 法线坐标
        let normals = [
            0.0, 0.0, 1.0,
            0.0, 0.0, 1.0,
            0.0, 0.0, 1.0,
            0.0, 0.0, 1.0,
        ];

        // 纹理坐标
        let textureIndies = [
            //top
            0.0, 0.0,
            1.0, 0.0,
            1.0, 1.0,
            0.0, 1.0,
        ];

        const positionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);


        const normalBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW);


        const texcoordBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureIndies), gl.STATIC_DRAW);

        return {
            positions: positionBuffer,
            textureIndies: texcoordBuffer,
            normals: normalBuffer,
        }
    }

    function initProgramInfo() {

        let vsSource = `
            attribute vec4 aVertexPosition;
            attribute vec3 aNormal; //法线
            attribute vec2 aTextureCoord;

            uniform vec3 uLightWorldPosition;
            uniform vec3 uViewWorldPosition;
            uniform mat4 uProjectionMatrix;
            uniform mat4 uViewMatrix;
            uniform mat4 uModelMatrix;
            uniform mat4 uNormalMatrix;

            uniform vec3 uAmbientLight;    //环境光颜色
            varying vec4 vColor;
            varying vec2 vTextureCoord;
            varying vec3 v_normal;
            varying vec3 v_surfaceToLight;
            varying vec3 v_surfaceToView;
            varying vec3 v_ambient;
            
            void main() {
                mat4 mvpMatrix = uProjectionMatrix  *uViewMatrix * uModelMatrix;
                gl_Position = mvpMatrix * aVertexPosition;
                vTextureCoord = aTextureCoord;
                v_normal = mat3(uNormalMatrix) * aNormal;
                vec3 surfaceWorldPosition = (uModelMatrix * aVertexPosition).xyz;
                v_surfaceToLight = uLightWorldPosition - surfaceWorldPosition;
                v_surfaceToView  = uViewWorldPosition - surfaceWorldPosition;
                v_ambient = uAmbientLight;
            }`;

        let fsSource = `            
            precision mediump float;
            uniform float u_shininess;
            uniform vec3  u_lightDirection;
            uniform vec3  u_lightColor;
            uniform float u_innerLimit;          // in dot space
            uniform float u_outerLimit;          // in dot space
            uniform sampler2D uSampler;

            varying vec2 vTextureCoord;
            varying vec3 v_normal;        
            varying vec3 v_surfaceToLight;
            varying vec3 v_surfaceToView;
            varying vec3 v_ambient;

            void main() {            
                vec4 texColor = texture2D(uSampler, vTextureCoord);
                vec3 normal = normalize(v_normal);
                vec3 surfaceToLightDirection = normalize(v_surfaceToLight);
                vec3 surfaceToViewDirection = normalize(v_surfaceToView);
                vec3 halfVector = normalize(surfaceToLightDirection + surfaceToViewDirection);

                float dotFromDirection = dot(surfaceToLightDirection,-u_lightDirection);
                float inLight = smoothstep(u_outerLimit, u_innerLimit, dotFromDirection);
                float light = inLight * dot(normal, surfaceToLightDirection);
                float specular = inLight * pow(dot(normal, halfVector), u_shininess);

                vec3 lightColor = u_lightColor.rgb *light;
                vec3 diffuse = texColor.rgb * light;  // + specular;
                vec3 ambient = v_ambient * texColor.rgb ;
                gl_FragColor = vec4(diffuse * lightColor  + ambient, texColor.a);
            }`;

        const shaderProgram = initShaderProgram(device, vsSource, fsSource);
        return {
            program: shaderProgram,
            attribLocations: {
                vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
                textureCoord: gl.getAttribLocation(shaderProgram, "aTextureCoord"),
                normalPosition: gl.getAttribLocation(shaderProgram, "aNormal")
            },
            uniformLocations: {
                projectionMatrix: gl.getUniformLocation(shaderProgram, "uProjectionMatrix"),
                lightPosition: gl.getUniformLocation(shaderProgram, 'uLightWorldPosition'),
                cameraPosition: gl.getUniformLocation(shaderProgram, 'uViewWorldPosition'),
                viewMatrix: gl.getUniformLocation(shaderProgram, "uViewMatrix"),
                modelMatrix: gl.getUniformLocation(shaderProgram, "uModelMatrix"),
                normalMatrix: gl.getUniformLocation(shaderProgram, 'uNormalMatrix'),
                ambientLight: gl.getUniformLocation(shaderProgram, 'uAmbientLight'),
                sampler: gl.getUniformLocation(shaderProgram, "uSamper"),
                shininess: gl.getUniformLocation(shaderProgram, "u_shininess"),
                lightDirection: gl.getUniformLocation(shaderProgram, "u_lightDirection"),
                innerLimit: gl.getUniformLocation(shaderProgram, "u_innerLimit"),
                outerLimit: gl.getUniformLocation(shaderProgram, "u_outerLimit"),
                lightColor: gl.getUniformLocation(shaderProgram, "u_lightColor"),

            },
        };
    }

    let modelMatrix = new Matrix4();
    const scaleFactor = floorSize / 2.0;
    modelMatrix.scale(scaleFactor, scaleFactor, scaleFactor);

    // 模型矩阵的逆矩阵
    let normalMatrix = new Matrix4();
    normalMatrix.setInverseOf(modelMatrix);
    normalMatrix.transpose();

    const buffers = g_floorInfo.buffers;
    const programInfo = g_floorInfo.programInfo;

    // 画立方体
    gl.useProgram(programInfo.program);

    gl.uniformMatrix4fv(programInfo.uniformLocations.projectionMatrix, false, d.projectionMatrix.elements);
    gl.uniformMatrix4fv(programInfo.uniformLocations.viewMatrix, false, d.viewMatrix.elements);
    gl.uniformMatrix4fv(programInfo.uniformLocations.modelMatrix, false, modelMatrix.elements);
    gl.uniformMatrix4fv(programInfo.uniformLocations.normalMatrix, false, normalMatrix.elements);

    // 设置灯光的位置
    gl.uniform3fv(programInfo.uniformLocations.lightPosition, lightCubePos);

    gl.uniform3fv(programInfo.uniformLocations.lightColor, pointlight);
    // lookat 位置
    gl.uniform3fv(programInfo.uniformLocations.cameraPosition, cameraPos);

    // ambientColor
    gl.uniform3fv(programInfo.uniformLocations.ambientLight, ambientLight)

    // shiness
    gl.uniform1f(programInfo.uniformLocations.shininess, shininess);

    {
        let matrixRotation = new Matrix4();
        matrixRotation.rotate(lightRotationY, 0, 1, 0).rotate(lightRotationX, 1, 0, 0)
        let lightDir = new Vector3(lightCubePos)

        let dir = matrixRotation.multiplyVector3(lightDir).normalize();
        lightDirection = [-dir.elements[0], -dir.elements[1], -dir.elements[2]];
        console.log("direction", lightDirection);
        // 
    }
    // 灯光位置
    gl.uniform3fv(programInfo.uniformLocations.lightDirection, lightDirection);

    // 内径
    gl.uniform1f(programInfo.uniformLocations.innerLimit, Math.cos(degToRad(innerLimit)));

    // 外径
    gl.uniform1f(programInfo.uniformLocations.outerLimit, Math.cos(degToRad(outerLimit)));


    // // 设置位置属性
    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.positions);
    gl.vertexAttribPointer(programInfo.attribLocations.vertexPosition, 3, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);

    //normal
    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.normals);
    gl.vertexAttribPointer(programInfo.attribLocations.normalPosition, 3, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(programInfo.attribLocations.normalPosition);


    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.textureIndies);
    gl.vertexAttribPointer(programInfo.attribLocations.textureCoord, 2, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(programInfo.attribLocations.textureCoord);

    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, d.texture);
    gl.uniform1i(programInfo.uniformLocations.sampler, 0);

    gl.drawArrays(gl.TRIANGLE_FAN, 0, 4)
}

//画灯光立方体
function drawLightCube(lightSize, lightPos) {
    console.log("drawLightCube -> ", lightSize, lightPos);
    if (!g_LightCubeInfo) {
        g_LightCubeInfo = {
            buffers: initCubeBuffer(),
            programInfo: initCubeProgramInfo(),
        }
    }

    function initCubeBuffer() {

        let positions = d.cubeData.positions
        let colors = d.cubeData.colors;
        let indices = d.cubeData.indices;

        const positionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

        const colorBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);


        const indexBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);


        return {
            positions: positionBuffer,
            colors: colorBuffer,
            indices: indexBuffer,
        };
    }

    // 立方体的信息
    function initCubeProgramInfo() {

        let vsSource = `
        attribute vec4 aVertexPosition;
        attribute vec4 aVertexColor;
        uniform mat4 uProjectionMatrix;
        uniform mat4 uViewMatrix;
        uniform mat4 uModelMatrix;
        varying vec4 vColor;
        void main() {
            gl_Position = uProjectionMatrix  *uViewMatrix * uModelMatrix * aVertexPosition;
            vColor = aVertexColor;
        }`;


        var fsSource = `
        #ifdef GL_ES
        precision mediump float;
        #endif
        varying vec4 vColor;
        void main() {
            gl_FragColor= vColor;
        }`;

        const shaderProgram = initShaderProgram(device, vsSource, fsSource);
        return {
            program: shaderProgram,
            attribLocations: {
                vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
                vertexColor: gl.getAttribLocation(shaderProgram, "aVertexColor"),
            },
            uniformLocations: {
                projectionMatrix: gl.getUniformLocation(shaderProgram, "uProjectionMatrix"),
                viewMatrix: gl.getUniformLocation(shaderProgram, "uViewMatrix"),
                modelMatrix: gl.getUniformLocation(shaderProgram, "uModelMatrix"),
            },
        };
    }

    // delete modelMatrix;
    // modelMatrix = null;
    let modelMatrix = new Matrix4();
    modelMatrix.setIdentity();
    console.log("modelMatrix", modelMatrix);
    const scaleFactor = lightSize / 2.0;


    modelMatrix.setTranslate(...lightPos).scale(scaleFactor, scaleFactor, scaleFactor);

    const buffers = g_LightCubeInfo.buffers;
    const programInfo = g_LightCubeInfo.programInfo;

    // 画立方体
    gl.useProgram(programInfo.program);

    gl.uniformMatrix4fv(programInfo.uniformLocations.projectionMatrix, false, d.projectionMatrix.elements);
    gl.uniformMatrix4fv(programInfo.uniformLocations.viewMatrix, false, d.viewMatrix.elements);
    gl.uniformMatrix4fv(programInfo.uniformLocations.modelMatrix, false, modelMatrix.elements);
    //  gl.uniformMatrix4fv(programInfo.uniformLocations.mvpMatrix,false,(d.projectionMatrix.multiply(d.viewMatrix)).elements);

    // 设置位置属性
    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.positions);
    gl.vertexAttribPointer(programInfo.attribLocations.vertexPosition, 3, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);

    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.colors);
    gl.vertexAttribPointer(programInfo.attribLocations.vertexColor, 4, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(programInfo.attribLocations.vertexColor);

    // indies
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices);
    gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);

    modelMatrix = null;

}

// 这个需要纹理
function drawBox(boxSize, boxPos) {
    console.log("drawBox -> ", boxSize, boxPos);
    if (!g_boxInfo) {
        g_boxInfo = {
            buffers: initBuffer(),
            programInfo: initProgramInfo(),
        }
    }

    function initBuffer() {
        let positions = d.cubeData.positions
        let textureIndies = d.cubeData.textureIndies;
        let colors = d.cubeData.colors;
        let indices = d.cubeData.indices;
        let normals = d.cubeData.normals;

        const positionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);


        const texcoordBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureIndies), gl.STATIC_DRAW);

        const colorBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);


        const normalBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW);


        const indexBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);

        return {
            positions: positionBuffer,
            textureIndies: texcoordBuffer,
            colors: colorBuffer,
            indices: indexBuffer,
            normals: normalBuffer,
        };
    }

    function initProgramInfo() {

        let vsSource = `
        attribute vec4 aVertexPosition;
        attribute vec2 aTextureCoord;
        attribute vec3 aNormal; //法线

        uniform vec3 uLightWorldPosition;
        uniform vec3 uViewWorldPosition;
        uniform mat4 uProjectionMatrix;  
        uniform mat4 uViewMatrix;
        uniform mat4 uModelMatrix;  
        uniform mat4 uNormalMatrix; 

        uniform vec3 uAmbientLight;    //环境光颜色

        varying vec2 vTextureCoord;
        varying vec3 v_normal;
        varying vec3 v_surfaceToLight;
        varying vec3 v_surfaceToView;
        varying vec3 v_ambient;

        void main() {
            mat4 mvpMatrix = uProjectionMatrix  *uViewMatrix * uModelMatrix;
            gl_Position = mvpMatrix * aVertexPosition;
            vTextureCoord = aTextureCoord;
            v_normal = mat3(uNormalMatrix) * aNormal;
            vec3 surfaceWorldPosition = (uModelMatrix * aVertexPosition).xyz;
            v_surfaceToLight = uLightWorldPosition - surfaceWorldPosition;
            v_surfaceToView  = uViewWorldPosition - surfaceWorldPosition;
            v_ambient = uAmbientLight;
        }`;


        let fsSource = `
        #ifdef GL_ES
        precision mediump float;
        #endif
        
       
        uniform float u_shininess;
        uniform vec3  u_lightDirection;
        uniform float u_innerLimit;          // in dot space
        uniform float u_outerLimit;          // in dot space
        uniform sampler2D uSampler;

        // varying vec4 vColor;
        varying vec2 vTextureCoord;
        varying vec3 v_normal;        
        varying vec3 v_surfaceToLight;
        varying vec3 v_surfaceToView;
        varying vec3 v_ambient;

        void main() {            
            vec4 texColor = texture2D(uSampler, vTextureCoord);
            vec3 normal = normalize(v_normal);
            vec3 surfaceToLightDirection = normalize(v_surfaceToLight);
            vec3 surfaceToViewDirection = normalize(v_surfaceToView);
            vec3 halfVector = normalize(surfaceToLightDirection + surfaceToViewDirection);

            float dotFromDirection = dot(surfaceToLightDirection,-u_lightDirection);
            float inLight = smoothstep(u_outerLimit, u_innerLimit, dotFromDirection);
            float light = inLight * dot(normal, surfaceToLightDirection);
            float specular = inLight * pow(dot(normal, halfVector), u_shininess);

            vec3 diffuse = texColor.rgb * light;  // + specular;
            vec3 ambient = v_ambient * texColor.rgb ;
            gl_FragColor = vec4(diffuse + ambient, texColor.a);
        }`;

        const shaderProgram = initShaderProgram(device, vsSource, fsSource);
        return {
            program: shaderProgram,
            attribLocations: {
                vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
                textureCoord: gl.getAttribLocation(shaderProgram, "aTextureCoord"),
                normalPosition: gl.getAttribLocation(shaderProgram, "aNormal")
            },
            uniformLocations: {
                projectionMatrix: gl.getUniformLocation(shaderProgram, "uProjectionMatrix"),
                lightPosition: gl.getUniformLocation(shaderProgram, 'uLightWorldPosition'),
                cameraPosition: gl.getUniformLocation(shaderProgram, 'uViewWorldPosition'),
                viewMatrix: gl.getUniformLocation(shaderProgram, "uViewMatrix"),
                modelMatrix: gl.getUniformLocation(shaderProgram, "uModelMatrix"),
                normalMatrix: gl.getUniformLocation(shaderProgram, 'uNormalMatrix'),
                ambientLight: gl.getUniformLocation(shaderProgram, 'uAmbientLight'),
                sampler: gl.getUniformLocation(shaderProgram, "uSamper"),
                shininess: gl.getUniformLocation(shaderProgram, "u_shininess"),
                lightDirection: gl.getUniformLocation(shaderProgram, "u_lightDirection"),
                innerLimit: gl.getUniformLocation(shaderProgram, "u_innerLimit"),
                outerLimit: gl.getUniformLocation(shaderProgram, "u_outerLimit"),
            },
        };
    }

    function render() {
        console.log("render -> drawBox");

        const scaleFactor = boxSize / 2.0;
        let modelMatrix = new Matrix4();
        console.log("modelMatrix", modelMatrix);
        modelMatrix.setTranslate(...boxPos).scale(scaleFactor, scaleFactor, scaleFactor);
        const buffers = g_boxInfo.buffers;
        const programInfo = g_boxInfo.programInfo;
        gl.useProgram(programInfo.program);

        // 模型矩阵的逆矩阵
        let normalMatrix = new Matrix4();
        normalMatrix.setInverseOf(modelMatrix);
        normalMatrix.transpose();

        gl.uniformMatrix4fv(programInfo.uniformLocations.projectionMatrix, false, d.projectionMatrix.elements);
        gl.uniformMatrix4fv(programInfo.uniformLocations.viewMatrix, false, d.viewMatrix.elements);
        gl.uniformMatrix4fv(programInfo.uniformLocations.modelMatrix, false, modelMatrix.elements);
        gl.uniformMatrix4fv(programInfo.uniformLocations.normalMatrix, false, normalMatrix.elements);

        // 设置灯光的位置
        gl.uniform3fv(programInfo.uniformLocations.lightPosition, lightCubePos);

        // lookat 位置
        gl.uniform3fv(programInfo.uniformLocations.cameraPosition, cameraPos);

        // ambientColor
        gl.uniform3fv(programInfo.uniformLocations.ambientLight, ambientLight)

        // shiness
        gl.uniform1f(programInfo.uniformLocations.shininess, shininess);


        {


            let lmat2 = m4.lookAt(lightCubePos, [0, 0, 0], [0, 1, 0]);
            lmat2 = m4.multiply(m4.xRotation(degToRad(lightRotationX)), lmat2); // 绕着x轴旋转
            lmat2 = m4.multiply(m4.yRotation(degToRad(lightRotationY)), lmat2); //绕着Y轴旋转
            // console.log("lmat2",lmat2);
            lightDirection = [-lmat2[8], -lmat2[9], -lmat2[10]];
            console.log("direction", lightDirection);

            let matrixRotation = new Matrix4();
            matrixRotation.rotate(lightRotationY, 0, 1, 0).rotate(lightRotationX, 1, 0, 0)
            let lightDir = new Vector3(lightCubePos)

            let dir = matrixRotation.multiplyVector3(lightDir).normalize();
            lightDirection = [-dir.elements[0], -dir.elements[1], -dir.elements[2]];
            console.log("direction", lightDirection);
            // 
        }

        // 灯光位置
        gl.uniform3fv(programInfo.uniformLocations.lightDirection, lightDirection);

        // 内径
        gl.uniform1f(programInfo.uniformLocations.innerLimit, Math.cos(degToRad(innerLimit)));

        // 外径
        gl.uniform1f(programInfo.uniformLocations.outerLimit, Math.cos(degToRad(outerLimit)));


        // // 设置位置属性
        gl.bindBuffer(gl.ARRAY_BUFFER, buffers.positions);
        gl.vertexAttribPointer(programInfo.attribLocations.vertexPosition, 3, gl.FLOAT, false, 0, 0);
        gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);

        //normal
        gl.bindBuffer(gl.ARRAY_BUFFER, buffers.normals);
        gl.vertexAttribPointer(programInfo.attribLocations.normalPosition, 3, gl.FLOAT, false, 0, 0);
        gl.enableVertexAttribArray(programInfo.attribLocations.normalPosition);

        gl.bindBuffer(gl.ARRAY_BUFFER, buffers.textureIndies);
        gl.vertexAttribPointer(programInfo.attribLocations.textureCoord, 2, gl.FLOAT, false, 0, 0);
        gl.enableVertexAttribArray(programInfo.attribLocations.textureCoord);

        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(gl.TEXTURE_2D, d.cubeTexture);
        gl.uniform1i(programInfo.uniformLocations.sampler, 0);

        // // indies
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices);
        gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);

    }

    render();
}